package org.jfsm.core;

import java.util.ArrayList;
import java.util.HashMap;

import org.jfsm.log.LogSource;

public class FSMLogger extends LogSource {

    String[] state;
    String[] signal;

    public void created(FSMWorker worker) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("Created: ");
        sb.append(worker.toDebugString());
        sb.append("\n");
        log(sb.toString());
    }

    public void ignored(InstanceState context, int stateID, int eventID) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("Context is on terminal state. Ignored signal.\n");
        sb.append("context:");
        sb.append(context.toString());
        sb.append(", state:");
        sb.append(state[stateID]);
        sb.append(", signal:");
        sb.append(signal[eventID]);
        sb.append("\n");
        log(sb.toString());
    }

    public void event(InstanceState context, int stateID, int eventID, Object message) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("signal, ");
        sb.append("context:");
        sb.append(context.toString());
        sb.append(", state:");
        sb.append(state[stateID]);
        sb.append(", event:");
        sb.append(signal[eventID]);
        if (message != null) {
            sb.append(", message:");
            sb.append(message.toString());
        }
        sb.append("\n");
        log(sb.toString());
    }

    public void transition(InstanceState context, int st1, int st2, int eventID, Object message) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("transition, ");
        sb.append("context:");
        sb.append(context.toString());
        if (st1 != st2) {
            sb.append(", state:");
            sb.append(state[st1]);
            sb.append("->");
            sb.append(state[st2]);
        }
        if (eventID != -1) {
            sb.append(", next signal:");
            sb.append(signal[eventID]);
            if (message != null) {
                sb.append(", message:");
                sb.append(message.toString());
            }
        }
        sb.append("\n");
        log(sb.toString());
    }

    public void invalid(InstanceState context, Object message) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("invalid transition, ");
        sb.append("context:");
        sb.append(context.toString());
        if (message != null) {
            sb.append(", message:");
            sb.append(message.toString());
        }
        sb.append("\n");
        log(sb.toString());
    }

    public void submitting(InstanceState context, int eventID, Object message) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("submitting, ");
        sb.append("context:");
        sb.append(context.toString());
        if (eventID == FSMWorker.SESSION_SIGNAL) {
            sb.append(", replyTo:");
            sb.append(((SessionMessage) message).replyCtx.ctx);
            eventID = ((SessionMessage) message).eventID;
            message = ((SessionMessage) message).message;
        }
        sb.append(", signal:");
        sb.append(signal[eventID]);
        if (message != null) {
            sb.append(", message:");
            sb.append(message.toString());
        }
        sb.append("\n");
        log(sb.toString());
    }

    public void session(InstanceState context, int stateID, SessionMessage sm) {
        if (!enabled)
            return;
        StringBuilder sb = newSB();
        sb.append("Session Message received, ");
        sb.append("context:");
        sb.append(context.toString());
        sb.append(", from:");
        sb.append(sm.replyCtx.ctx.toString());
        sb.append(", state:");
        sb.append(state[stateID]);
        sb.append(", event:");
        sb.append(signal[sm.eventID]);
        if (sm.message != null) {
            sb.append(", message:");
            sb.append(sm.message.toString());
        }
        sb.append("\n");
        log(sb.toString());
    }

    // ***********
    public void setStateMap(int size, HashMap<Class<?>, Integer> map) {
        state = createArray(size, map);
    }

    public void setSignalMap(ArrayList<String> signalNames) {
        signal = new String[signalNames.size()];
        signalNames.toArray(signal);
    }

    String[] createArray(int size, HashMap<Class<?>, Integer> map) {
        String[] a = new String[size];

        for (Class<?> cl : map.keySet()) {
            int offset = map.get(cl);
            Object[] ea = cl.getEnumConstants();
            if (ea != null) {
                for (int i = 0; i < ea.length; i++) {
                    a[offset + i] = ea[i].toString();
                }
            }
        }
        return a;
    }

}
